package my.georings.data;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Hashtable;

import my.Utils;
import android.content.Context;
import android.location.Location;

import com.google.android.maps.GeoPoint;


public class MyLocationsManager {

	
	private static int locationId = 0;
	private ArrayList<MyLocation> list = new ArrayList<MyLocation>();
	private Hashtable<Integer, MyLocation> table = new Hashtable<Integer, MyLocation>();
	private String FILENAME = "locations";
	private MyLocationsManagerListener managerListener = null;
	
	public MyLocationsManager(){
	}
	
	public boolean addLocation(MyLocation newLocation){
		list.add(newLocation);
		table.put(new Integer(newLocation.getId()), newLocation);
		
		newLocation.setParentManager(this);
		
		if(managerListener != null){
			managerListener.onLocationAdded(newLocation);
		}
		return true;
	}
	
	
	public void removeLocation(int id){
		MyLocation toRemove = table.remove(new Integer(id));
		list.remove(toRemove);
		
		toRemove.setParentManager(null);
		
		if(managerListener != null){
			managerListener.onLocationDeleted(toRemove);
		}
	}
	
	public void changeLocation(MyLocation editted){
		MyLocation toRemove = table.get(new Integer(editted.getId()));
		list.remove(toRemove);
		
		list.add(editted);
		table.put(new Integer(editted.getId()), editted);
		if(managerListener != null){
			managerListener.onLocationChanged(editted);
		}
	}
	
	public void changeLocationOnOff(MyLocation location){
		if(managerListener != null){
			managerListener.onLocationOnOff(location);
		}
	}
	
	public static int getLocationId(){
		++locationId;
		return (locationId-1);
	}
	
	public ArrayList<MyLocation> getList() {
		return list;
	}

	public void serialize(Context context) throws IOException{
		FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
		ObjectOutputStream out = new ObjectOutputStream(fos);
		
		out.writeInt(locationId);
		out.writeInt(list.size());
		
		for(int i = 0; i < list.size(); ++i){
			out.writeObject((Object)list.get(i));
		}
		out.close();
	}
	
	public void deserialize(Context context) throws IOException{
		
		FileInputStream fis = context.openFileInput(FILENAME);
		
		ObjectInputStream in = new ObjectInputStream(fis);
		
		locationId = in.readInt();
		int size = in.readInt();
		
		for(int i = 0; i < size; ++i){
			try {
				MyLocation location = (MyLocation)in.readObject();
				list.add(location);
				table.put(new Integer(location.getId()), location);
				location.setParentManager(this);
			} catch (ClassNotFoundException e) {
				break;
			}	
		}
	}

	
	public MyLocation getLocationOfId(int id){
		return table.get(new Integer(id));
	}


	
	public boolean isNewPointValid(GeoPoint point){
		Location newLocation = Utils.locationFromGeoPoint(point);
		for(int i = 0; i < list.size(); ++i){
			MyLocation loc = list.get(i);
			// too close to another known location
			if(loc.getLocation().distanceTo(newLocation) <= (float)(loc.getRadius()+300)){
				return false;
			}
		}
		return true;
	}
	
	
	public Hashtable<Float, MyLocation> getNearestLocation(Location currLocation){
		if(list.isEmpty())
			return null;
		
		float min = -1;
		MyLocation minLoc = null;
		for(int i = 0; i < list.size(); ++i){
			
			if(!list.get(i).isON())
				continue;
			else{
				minLoc = list.get(i);
				break;
			}
		}
		if(minLoc == null){
			return null;
		}
		
		min = minLoc.getLocation().distanceTo(currLocation) - minLoc.getRadius();
		
		for(int i = 1; i < list.size(); ++i){
			MyLocation loc = list.get(i);
			if(!loc.isON())
				continue;
			float dist = loc.getLocation().distanceTo(currLocation) - minLoc.getRadius();
			if(dist <= min){
				min = dist;
				minLoc = loc;
			}
		}
		
		
		Hashtable<Float, MyLocation> map = new Hashtable<Float, MyLocation>(1);
		map.put(new Float(min), minLoc);
		return map;
	}
	
	public int getSize(){
		return list.size();
	}

	public MyLocationsManagerListener getManagerListener() {
		return managerListener;
	}

	public void setManagerListener(MyLocationsManagerListener managerListener) {
		this.managerListener = managerListener;
	}

	
}
